package cool.lichuan.zabbix.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cool.lichuan.zabbix.config.ZabbixProperties;
import cool.lichuan.zabbix.constant.CommonField;
import cool.lichuan.zabbix.domain.graph.graph.GraphResult;
import cool.lichuan.zabbix.domain.graph.item.GraphItemResult;
import cool.lichuan.zabbix.domain.host.group.HostGroup;
import cool.lichuan.zabbix.domain.host.group.HostGroupResult;
import cool.lichuan.zabbix.domain.host.host.Host;
import cool.lichuan.zabbix.domain.host.host.HostResult;
import cool.lichuan.zabbix.domain.host.hostinterface.HostInterface;
import cool.lichuan.zabbix.domain.host.hostinterface.HostInterfaceResult;
import cool.lichuan.zabbix.domain.problem.Problem;
import cool.lichuan.zabbix.domain.problem.ProblemHost;
import cool.lichuan.zabbix.domain.problem.ProblemParam;
import cool.lichuan.zabbix.domain.problem.ProblemResult;
import cool.lichuan.zabbix.request.ApiMethodName;
import cool.lichuan.zabbix.request.Request;
import cool.lichuan.zabbix.request.Requester;
import cool.lichuan.zabbix.service.ZabbixApiService;
import cool.lichuan.zabbix.util.DateUtil;
import cool.lichuan.zabbix.util.FieldBuilder;
import cool.lichuan.zabbix.util.ParamBuilder;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author LiChuan
 * @date 2021/11/4 10:12
 */
public class ZabbixApiServiceImpl implements ZabbixApiService {

    @Resource
    private ZabbixProperties zabbixProperties;

    private volatile String auth;
    private LocalDateTime authRefreshTime;

    private static final HttpClient HTTP_CLIENT = HttpClients.createDefault();

    private static final Logger log = LoggerFactory.getLogger(ZabbixApiServiceImpl.class);
    //--------------------- 事件、问题类API开始 --------------------//

    /**
     * 获取问题信息
     *
     * @param params 请求参数
     * @return 返回
     */
    @Override
    public ProblemResult getProblem(HashMap<String, Object> params) {
        Request request = Requester.getRequester(ApiMethodName.PROBLEM_GET, params);
        return this.call(request, ProblemResult.class);
    }


    //--------------------- 事件、问题类API结束 --------------------//

    //--------------------- 主机类API开始 -------------------------//

    /**
     * 获取主机接口列表
     *
     * @param params 参数
     * @return 返回
     */
    @Override
    public HostInterfaceResult getHostInterface(HashMap<String, Object> params) {
        Request request = Requester.getRequester(ApiMethodName.HOST_INTERFACE_GET, params);
        return this.call(request, HostInterfaceResult.class);
    }

    /**
     * 获取主机列表
     *
     * @param params 参数
     * @return 返回
     */
    @Override
    public HostResult getHosts(HashMap<String, Object> params) {
        if (null == params) {
            params = new HashMap<>(16);
        } else {
            if (!params.containsKey(CommonField.PARAM_OUT_PUT)) {
                params.put(CommonField.PARAM_OUT_PUT, FieldBuilder.respFieldBuild(Host::getHostId, Host::getHost));
            }
            // 如未设定主机接口信息，默认查询主机接口ID和IP
            if (!params.containsKey(CommonField.PARAM_SELECT_INTERFACES)) {
                params.put(CommonField.PARAM_SELECT_INTERFACES, FieldBuilder.respFieldBuild(HostInterface::getInterfaceid, HostInterface::getIp));
            }
        }
        Request request = Requester.getRequester(ApiMethodName.HOST_GET, params);
        return this.call(request, HostResult.class);
    }

    /**
     * 获取主机组
     *
     * @param params 参数
     * @return 返回
     */
    @Override
    public HostGroupResult getHostGroup(HashMap<String, Object> params) {
        Request request = Requester.getRequester(ApiMethodName.HOST_GROUP_GET, params);
        return this.call(request, HostGroupResult.class);
    }

    /**
     * 查询问题主机信息
     *
     * @param problemParam 问题参数
     * @return 返回
     */
    @Override
    public List<ProblemHost> getProblemHosts(ProblemParam problemParam) {
        List<ProblemHost> resultList = new ArrayList<>();
        String[] groupIds = null != problemParam && StringUtils.hasLength(problemParam.getGroupId()) ? new String[]{problemParam.getGroupId()} : null;
        HashMap<String, Object> params = ParamBuilder.builder().put("groupids", groupIds).put("selectGroups", "extend")
                .output(new String[]{"hostid", "host"}).build();
        HostResult hostResult = getHosts(params);
        if (null == hostResult.getError()) {
            List<Host> hostList = hostResult.getResult();
            if (!CollectionUtils.isEmpty(hostList)) {
                // 此处为了将主机数据绑定到
                for (Host host : hostList) {
                    ProblemResult problemResult = getProblem(ParamBuilder.builder().put("hostids", new String[]{host.getHostId()})
                            .output(new String[]{"eventid", "clock", "severity", "suppressed", "name", "acknowledged"}).build());
                    if (null == problemResult.getError()) {
                        List<Problem> problemList = problemResult.getResult();
                        for (Problem problem1 : problemList) {
                            ProblemHost problemHost = new ProblemHost();
                            problemHost.setEventId(problem1.getEventId());
                            if(null != problem1.getClock()) {
                                problemHost.setCreateTime(new Date(problem1.getClock() * 1000));
                            }
                            problemHost.setSeverity(problem1.getSeverity());
                            problemHost.setSuppressed(problem1.getSuppressed());
                            problemHost.setName(problem1.getName());
                            problemHost.setDuration(DateUtil.getDateDurations(problem1.getClock(), problem1.getrClock()));
                            problemHost.setAcknowledged(problem1.getAcknowledged());
                            problemHost.setHostId(host.getHostId());
                            problemHost.setHostName(host.getHost());

                            List<HostGroup> groups = host.getGroups();
                            String groupNames = "";
                            if (!CollectionUtils.isEmpty(groups)) {
                                groupNames = groups.stream().map(HostGroup::getName).collect(Collectors.joining("、"));
                                List<String> groupIdList = groups.stream().map(HostGroup::getGroupId).collect(Collectors.toList());
                                problemHost.setGroupIds(groupIdList);
                            }
                            problemHost.setGroupNames(groupNames);
                            resultList.add(problemHost);
                        }
                    }
                }
            }
        }
        return resultList;
    }
    //--------------------- 主机类API开始 -------------------------//

    //--------------------- 图表类API开始 -------------------------//

    /**
     * 获取图表信息
     *
     * @param params 参数
     * @return 返回
     */
    @Override
    public GraphResult getGraph(HashMap<String, Object> params) {
        Request request = Requester.getRequester(ApiMethodName.GRAPH_GET, params);
        return this.call(request, GraphResult.class);
    }

    /**
     * 获取图表监控信息
     *
     * @param params 参数
     * @return 返回
     */
    @Override
    public GraphItemResult getGraphItem(HashMap<String, Object> params) {
        Request request = Requester.getRequester(ApiMethodName.GRAPH_ITEM_GET, params);
        return this.call(request, GraphItemResult.class);
    }
    //--------------------- 图表类API结束 -------------------------//

    /**
     * 登录，获取auth
     */
    @Override
    public void login() {
        if (!checkAuth()) {
            Request request = Requester.builder().method(ApiMethodName.LOGIN)
                    .param("user", zabbixProperties.getUserName())
                    .param("password", zabbixProperties.getPassword()).build();
            JSONObject http = this.http(request);
            if (null != http && null == http.get(CommonField.RESP_ERROR)) {
                String auth = http.getString(CommonField.RESP_RESULT);
                if (StringUtils.hasLength(auth)) {
                    this.auth = auth;
                    this.authRefreshTime = LocalDateTime.now();
                    return;
                }
            }
            throw new RuntimeException("Auth获取失败，请检查url、userName和password设置是否正确！");
        }
    }

    /**
     * 返回请求jsonObject
     *
     * @param request 请求信息
     * @return 返回
     */
    @Override
    public JSONObject call(Request request) {
        this.login();
        if (null == request.getAuth()) {
            request.setAuth(this.auth);
        }
        return this.http(request);
    }

    /**
     * 返回解析的具体实体类
     *
     * @param request 请求
     * @param clazz   解析类
     * @param <T>     泛型
     * @return 返回
     */
    @Override
    public <T> T call(Request request, Class<T> clazz) {
        JSONObject call = this.call(request);
        return JSON.toJavaObject(call, clazz);
    }

    @PostConstruct
    public void init() {
        this.login();
    }

    /**
     * 判断auth是否存在
     *
     * @return false不存在  true存在
     */
    private boolean checkAuth() {
        if (!StringUtils.hasLength(this.auth) || null == this.authRefreshTime) {
            return false;
        }
        LocalDateTime now = LocalDateTime.now();
        Duration between = Duration.between(this.authRefreshTime, now);
        long seconds = between.getSeconds();
        return seconds < zabbixProperties.getAutoLogout() * 0.8;
    }

    /**
     * 发起请求
     *
     * @param request 请求
     * @return 返回
     */
    private JSONObject http(Request request) {
        try {
            // 构造请求
            HttpPost httpPost = new HttpPost(zabbixProperties.getUrl());
            httpPost.setHeader("Content-Type", "application/json");
            httpPost.setEntity(new StringEntity(JSON.toJSONString(request), ContentType.APPLICATION_JSON));
            // 发起请求
            HttpResponse response = HTTP_CLIENT.execute(httpPost);
            // 解析结果
            HttpEntity entity = response.getEntity();
            String entityStr = EntityUtils.toString(entity);
            return JSON.parseObject(entityStr);
        } catch (IOException e) {
            log.error("请求错误，方法名：{}；错误信息{}", request.getMethod(), e.getMessage());
        }
        return null;
    }
}
